/*******************************************************************************
 * Copyright (c) 2012, 2013 XML-Print Project.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     XML-Print Project - initial API and implementation
 ******************************************************************************/
package info.xmlprint.core.xml;

import info.xmlprint.ui.message.GuiMessages;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.dom4j.io.SAXReader;
import org.eclipse.jface.dialogs.MessageDialog;
import org.jaxen.JaxenException;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.dom4j.Dom4jXPath;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/*
 * die Klasse sammelt alle exisitierte Path in originalem XML
 */
public class XMLScanner {
	private Logger logger = Logger.getLogger(this.getClass().getName());

	private Map<String, String> simpleXmlMap = new HashMap<String, String>();
	private Document simpleDoc;
	private Map<String, String> namespaceMap = new HashMap<String, String>();

	public static void main(String args[]) {
		XMLScanner simpleXmlOfInput = new XMLScanner();
		try {
			simpleXmlOfInput.setInput(new InputSource(new FileInputStream(
					"e://testdokument.xml")));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		Document doc = simpleXmlOfInput.getXml();

		List<Element> list = simpleXmlOfInput.getDocNodes(
				"//publicationStmt/pp:dir", doc, new SimpleNamespaceContext(
						simpleXmlOfInput.getNamespaceMap()));

		System.out.println(list.size() + doc.asXML());
	}

	public void setInput(InputSource is) {
		Document document = null;
		try {
			SAXReader saxReader = new SAXReader();
			saxReader.setEntityResolver(new EntityResolver() {
				@Override
				public InputSource resolveEntity(String publicId,
						String systemId) throws SAXException, IOException {
					logger.warn("Ignoring: " + publicId + ", " + systemId);
					return new org.xml.sax.InputSource(
							new java.io.StringReader(""));
				}
			});
			document = saxReader.read(is);
		} catch (DocumentException e) {
			Logger.getLogger(this.getClass().getName()).error("", e);
			e.printStackTrace();
		}

		Element root = document.getRootElement();

		@SuppressWarnings("unchecked")
		List<Element> list = root.elements(); 
		add(list);

		simpleDoc = DocumentHelper.createDocument();
		Element newDocRoot = simpleDoc.addElement(root.getName());

		Iterator<Entry<String, String>> it = simpleXmlMap.entrySet().iterator();
		String path = null;
		while (it.hasNext()) {
			path = it.next().getKey();
			// System.out.println(path);
			pathToElement(newDocRoot, path);
		}
	}

	public Document getXml() {
		return simpleDoc;
	}

	public Map<String, String> getNamespaceMap() {
		return namespaceMap;
	}

	public SimpleNamespaceContext getSimpleNamespaceContext() {
		return new SimpleNamespaceContext(namespaceMap);
	}

	private Element pathToElement(Element root, String path) {
		Element e = null;
		String[] arr = path.split("\\/");
		String elem;
		String namespaceKey;

		// Elemente unter Wurzel
		for (int i = 2; i < arr.length; i++) {
			elem = arr[i];
			String[] elemArr = elem.split(":");
			if (i == 2) {
				if (elemArr.length > 1) {
					e = root.addElement(elemArr[1]);
					namespaceKey = elemArr[0];
					QName name = QName.get(elemArr[1], namespaceKey,
							namespaceMap.get(namespaceKey));
					e.setQName(name);

				} else
					e = root.addElement(elemArr[0]);

			} else {
				if (elemArr.length > 1) {
					e = e.addElement(elemArr[1]);
					namespaceKey = elemArr[0];
					QName name = QName.get(elemArr[1], namespaceKey,
							namespaceMap.get(namespaceKey));
					e.setQName(name);
				} else
					e = e.addElement(elemArr[0]);

			}

		}

		return e;
	}

	private void add(List<Element> list) {
		for (Element e : list) {

			String ePath = e.getPath();
			ePath = ePath.replaceAll("\\*\\[name\\(\\)\\=\\'", "");
			ePath = ePath.replaceAll("\\'\\]", "");
			String eName = e.getName();
			if (e.getNamespacePrefix() != null
					&& !e.getNamespacePrefix().equals(""))
				namespaceMap.put(e.getNamespacePrefix(), e.getNamespaceURI());

			@SuppressWarnings("unchecked")
			List<Element> li = e.elements();

			if (li.size() > 0)
				add(li);
			else {
				simpleXmlMap.put(ePath, eName);
			}
		}

	}

	@SuppressWarnings("unchecked")
	private List<Element> getDocNodes(String xPathStr, Object doc,
			SimpleNamespaceContext nsMap) {
		Dom4jXPath xPath = null;
		try {
			xPath = new Dom4jXPath(xPathStr);
		} catch (JaxenException e) {
			Logger.getLogger(this.getClass().getName()).error("", e);
			e.printStackTrace();
			MessageDialog.openError(null, GuiMessages.Stileditor_Error_Error,
					GuiMessages.Stileditor_Error_XPathError);
		}

		xPath.setNamespaceContext(nsMap);

		List<Element> list = null;
		try {

			list = xPath.selectNodes(doc);
		} catch (JaxenException e1) {
			Logger.getLogger(this.getClass().getName()).error("", e1);
			e1.printStackTrace();
			MessageDialog.openError(null, GuiMessages.Stileditor_Error_Error,
					GuiMessages.Stileditor_Error_XPathError);

		}
		return list;
	}

}
